import React, { SyntheticEvent, useState } from 'react';

import {
  DataSourcePluginOptionsEditorProps,
  onUpdateDatasourceJsonDataOption,
  onUpdateDatasourceSecureJsonDataOption,
  SelectableValue,
  updateDatasourcePluginJsonDataOption,
  updateDatasourcePluginResetOption,
} from '@grafana/data';
import {
  Alert,
  InlineSwitch,
  FieldSet,
  InlineField,
  InlineFieldRow,
  Input,
  Select,
  SecretInput,
  Link,
} from '@grafana/ui';
import { config } from 'app/core/config';
import { ConnectionLimits } from 'app/features/plugins/sql/components/configuration/ConnectionLimits';
import { TLSSecretsConfig } from 'app/features/plugins/sql/components/configuration/TLSSecretsConfig';
import { useMigrateDatabaseFields } from 'app/features/plugins/sql/components/configuration/useMigrateDatabaseFields';

import { PostgresOptions, PostgresTLSMethods, PostgresTLSModes, SecureJsonData } from '../types';

import { useAutoDetectFeatures } from './useAutoDetectFeatures';

export const postgresVersions: Array<SelectableValue<number>> = [
  { label: '9.0', value: 900 },
  { label: '9.1', value: 901 },
  { label: '9.2', value: 902 },
  { label: '9.3', value: 903 },
  { label: '9.4', value: 904 },
  { label: '9.5', value: 905 },
  { label: '9.6', value: 906 },
  { label: '10', value: 1000 },
  { label: '11', value: 1100 },
  { label: '12', value: 1200 },
  { label: '13', value: 1300 },
  { label: '14', value: 1400 },
  { label: '15', value: 1500 },
];

export const PostgresConfigEditor = (props: DataSourcePluginOptionsEditorProps<PostgresOptions, SecureJsonData>) => {
  const [versionOptions, setVersionOptions] = useState(postgresVersions);

  useAutoDetectFeatures({ props, setVersionOptions });

  useMigrateDatabaseFields(props);

  const { options, onOptionsChange } = props;
  const jsonData = options.jsonData;

  const onResetPassword = () => {
    updateDatasourcePluginResetOption(props, 'password');
  };

  const tlsModes: Array<SelectableValue<PostgresTLSModes>> = [
    { value: PostgresTLSModes.disable, label: 'disable' },
    { value: PostgresTLSModes.require, label: 'require' },
    { value: PostgresTLSModes.verifyCA, label: 'verify-ca' },
    { value: PostgresTLSModes.verifyFull, label: 'verify-full' },
  ];

  const tlsMethods: Array<SelectableValue<PostgresTLSMethods>> = [
    { value: PostgresTLSMethods.filePath, label: 'File system path' },
    { value: PostgresTLSMethods.fileContent, label: 'Certificate content' },
  ];

  const onJSONDataOptionSelected = (property: keyof PostgresOptions) => {
    return (value: SelectableValue) => {
      updateDatasourcePluginJsonDataOption(props, property, value.value);
    };
  };

  const onTimeScaleDBChanged = (event: SyntheticEvent<HTMLInputElement>) => {
    updateDatasourcePluginJsonDataOption(props, 'timescaledb', event.currentTarget.checked);
  };

  const onDSOptionChanged = (property: keyof PostgresOptions) => {
    return (event: SyntheticEvent<HTMLInputElement>) => {
      onOptionsChange({ ...options, ...{ [property]: event.currentTarget.value } });
    };
  };

  const labelWidthSSLDetails = 25;
  const labelWidthConnection = 20;
  const labelWidthShort = 20;

  return (
    <>
      <FieldSet label="PostgreSQL Connection" width={400}>
        <InlineField labelWidth={labelWidthConnection} label="Host">
          <Input
            width={40}
            name="host"
            type="text"
            value={options.url || ''}
            placeholder="localhost:5432"
            onChange={onDSOptionChanged('url')}
          ></Input>
        </InlineField>
        <InlineField labelWidth={labelWidthConnection} label="Database">
          <Input
            width={40}
            name="database"
            value={jsonData.database || ''}
            placeholder="database name"
            onChange={onUpdateDatasourceJsonDataOption(props, 'database')}
          ></Input>
        </InlineField>
        <InlineFieldRow>
          <InlineField labelWidth={labelWidthConnection} label="User">
            <Input value={options.user || ''} placeholder="user" onChange={onDSOptionChanged('user')}></Input>
          </InlineField>
          <InlineField label="Password">
            <SecretInput
              placeholder="Password"
              isConfigured={options.secureJsonFields?.password}
              onReset={onResetPassword}
              onBlur={onUpdateDatasourceSecureJsonDataOption(props, 'password')}
            ></SecretInput>
          </InlineField>
        </InlineFieldRow>
        <InlineField
          labelWidth={labelWidthConnection}
          label="TLS/SSL Mode"
          htmlFor="tlsMode"
          tooltip="此选项确定是否或以何种优先级与服务器协商安全的TLS/SSL TCP/IP连接."
        >
          <Select
            options={tlsModes}
            inputId="tlsMode"
            value={jsonData.sslmode || PostgresTLSModes.verifyFull}
            onChange={onJSONDataOptionSelected('sslmode')}
          ></Select>
        </InlineField>
        {options.jsonData.sslmode !== PostgresTLSModes.disable ? (
          <InlineField
            labelWidth={labelWidthConnection}
            label="TLS/SSL Method"
            htmlFor="tlsMethod"
            tooltip={
              <span>
                此选项确定如何配置TLS/SSL证书。选择<i>文件系统路径</i>将
                允许您通过指定本地文件上现有证书的路径来配置证书
                Grafana运行的系统。确保执行Grafana进程的用户能够读取该文件.
                <br />
                <br />
                选择 <i>证书内容</i> 将允许您通过指定证书的内容来配置证书.
                内容将加密存储在Grafana中&apos;的数据库。当连接到数据库时，
                证书将作为文件写入Grafana&apos;s在本地文件系统上配置的数据路径.
              </span>
            }
          >
            <Select
              options={tlsMethods}
              inputId="tlsMethod"
              value={jsonData.tlsConfigurationMethod || PostgresTLSMethods.filePath}
              onChange={onJSONDataOptionSelected('tlsConfigurationMethod')}
            ></Select>
          </InlineField>
        ) : null}
      </FieldSet>

      {config.secureSocksDSProxyEnabled && (
        <FieldSet label="Secure Socks Proxy">
          <InlineField labelWidth={26} label="Enabled" tooltip="通过安全socks代理连接到此数据源.">
            <InlineSwitch
              value={options.jsonData.enableSecureSocksProxy ?? false}
              onChange={(event) =>
                onOptionsChange({
                  ...options,
                  jsonData: { ...options.jsonData, enableSecureSocksProxy: event!.currentTarget.checked },
                })
              }
            />
          </InlineField>
        </FieldSet>
      )}
      {jsonData.sslmode !== PostgresTLSModes.disable ? (
        <FieldSet label="TLS/SSL Auth Details">
          {jsonData.tlsConfigurationMethod === PostgresTLSMethods.fileContent ? (
            <TLSSecretsConfig
              showCACert={
                jsonData.sslmode === PostgresTLSModes.verifyCA || jsonData.sslmode === PostgresTLSModes.verifyFull
              }
              editorProps={props}
              labelWidth={labelWidthSSLDetails}
            ></TLSSecretsConfig>
          ) : (
            <>
              <InlineField
                tooltip={
                  <span>
                    如果所选的TLS/SSL模式需要服务器根证书，请在此处提供文件的路径.
                  </span>
                }
                labelWidth={labelWidthSSLDetails}
                label="TLS/SSL Root Certificate"
              >
                <Input
                  value={jsonData.sslRootCertFile || ''}
                  onChange={onUpdateDatasourceJsonDataOption(props, 'sslRootCertFile')}
                  placeholder="TLS/SSL root cert file"
                ></Input>
              </InlineField>
              <InlineField
                tooltip={
                  <span>
                    要使用TLS/SSL客户端证书进行身份验证，请在此处提供文件的路径。确保执行grafana进程的用户能够读取该文件.
                  </span>
                }
                labelWidth={labelWidthSSLDetails}
                label="TLS/SSL Client Certificate"
              >
                <Input
                  value={jsonData.sslCertFile || ''}
                  onChange={onUpdateDatasourceJsonDataOption(props, 'sslCertFile')}
                  placeholder="TLS/SSL client cert file"
                ></Input>
              </InlineField>
              <InlineField
                tooltip={
                  <span>
                    要使用客户端TLS/SSL证书进行身份验证，请在此处提供相应密钥文件的路径。
                    请确保执行grafana进程的用户只能读取<i>文件</i>.
                  </span>
                }
                labelWidth={labelWidthSSLDetails}
                label="TLS/SSL Client Key"
              >
                <Input
                  value={jsonData.sslKeyFile || ''}
                  onChange={onUpdateDatasourceJsonDataOption(props, 'sslKeyFile')}
                  placeholder="TLS/SSL client key file"
                ></Input>
              </InlineField>
            </>
          )}
        </FieldSet>
      ) : null}

      <ConnectionLimits labelWidth={labelWidthShort} options={options} onOptionsChange={onOptionsChange} />

      <FieldSet label="PostgreSQL details">
        <InlineField
          tooltip="此选项控制PostgreSQL查询生成器中可用的函数"
          labelWidth={labelWidthShort}
          htmlFor="postgresVersion"
          label="Version"
        >
          <Select
            value={jsonData.postgresVersion || 903}
            inputId="postgresVersion"
            onChange={onJSONDataOptionSelected('postgresVersion')}
            options={versionOptions}
          ></Select>
        </InlineField>
        <InlineField
          tooltip={
            <span>
              TimescaleDB是作为PostgreSQL扩展构建的时间序列数据库. 如果启用，Grafana将使用
              <code>time_bucket</code> 在 <code>$__timeGroup</code> 宏，并在查询生成器中显示TimescaleDB特定的聚合函数.
            </span>
          }
          labelWidth={labelWidthShort}
          label="TimescaleDB"
          htmlFor="timescaledb"
        >
          <InlineSwitch
            id="timescaledb"
            value={jsonData.timescaledb || false}
            onChange={onTimeScaleDBChanged}
          ></InlineSwitch>
        </InlineField>
        <InlineField
          tooltip={
            <span>
              按时间间隔自动分组的下限。例如，建议设置为写入频率
              <code>1m</code> 如果您的数据是每分钟写入一次.
            </span>
          }
          labelWidth={labelWidthShort}
          label="Min time interval"
        >
          <Input
            placeholder="1m"
            value={jsonData.timeInterval || ''}
            onChange={onUpdateDatasourceJsonDataOption(props, 'timeInterval')}
          ></Input>
        </InlineField>
      </FieldSet>

      <Alert title="User Permission" severity="info">
        应仅向数据库用户授予对指定数据库的SELECT权限 &amp; 要查询的表.
        Grafana不会验证查询是否安全，因此查询可以包含任何SQL语句。例如,
        诸如 <code>DELETE FROM user;</code> and <code>DROP TABLE user;</code> 将被执行.
        为了防止这种情况，我们 <strong>Highly</strong> 建议您创建一个具有受限权限的特定PostgreSQL用户。查看{' '}
        <Link rel="noreferrer" target="_blank" href="http://docs.grafana.org/features/datasources/postgres/">
          PostgreSQL数据源文档
        </Link>{' '}
        更多信息.
      </Alert>
    </>
  );
};
